home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
BBS Toolkit
/
BBS Toolkit.iso
/
rbbs_pc
/
173aasm.zip
/
QBARCV6.ASM
< prev
next >
Wrap
Assembly Source File
|
1989-09-03
|
46KB
|
1,688 lines
page 74,132
title ARCV - Verbose ARC directory listing
; Special version of ARCV to be called by QB program
; usage:
;
; CALL ARCV (Workname$,"filename[.PAK]", RETCD%) ' CPC151AC
;
; notes:
; This code originated from ARCV 1.15d - Verbose ARC directory display
; written by V.Buerg and was modified to run as a called routine under
; Microsoft QuickBasic. It was further modified to allow PAK files by
; Robert J. Simoneau.
;
; Change 9/14/86 to dis-allow wildcards
; Change 1/1/87 to recognize squash format
; Change 2/18/87 to support network usage - - - - Jon Martin ' CPC151A
; Change 1/7/89 to support Pak files -------------Bob Simoneau
; Change 890320 to support ZIP files David Kirschbaum, Toad Hall
; - Question: Why do we "have to look for the damned thing" when it
; comes to finding ARC/PAK headers? All comments are at file ends,
; so the header should be EXACTLY where it should be .. at the end of
; the file's compressed code. Hacked severely to reflect this,
; and vastly cleaning up the code.
; - Replaced old SDIR Binary to Ascii conversion with a hacked version
; from JMODEM .. about 10 times faster, plus offers integer conversion
; as well as long integers.
;v1.3 - FAAR RBBS reports this sucker runs once and then just returns
; a usage message (in the output file).
; Trying to find out why. Found it .. dumb mistake, not clearing
; variables between runs.
; - Adding true EOF testing for file pointer bumps.
; ZIP files have a good way to find EOF (e.g., the central directory),
; but PAK and ARC files don't.
; - Added some more error msgs.
; - Tightened hex output (CvH).
; - Reduced buffer sizes to minimum (archdr and inbuf).
;
;v1.4 - Adding the new Japanese .LHZ capability. Toad Hall
; See LHARC10E.ZIP (available on GEnie and BBS's) for details.
; - Neatening up total line.
; - Found some bugs in trying to predetermine ARC/PAK EOF.
; Fixed (hopefully).
; - Added a bunch of [bx] references .. saved 100 bytes!
; - Credits for LHARC (.LHZ) file header structure to:
; Daniel Durbin
; SysOp: Cygnus X-1 BBS | CIS: 73447,1744
; (805) 541-8505 (data) | GEnie: D.DURBIN
; EL major at PolySlo | ddurbin@polyslo.CalPoly.EDU
; from his LVIEW.C code.
;
;Fix - Correct bug that kept version 1.4 from functioning when linked
;08/23/89 with RBBS-PC that had been compiled using QB4.5 compiler.
; As it turned out it was an out and out bug that just did not
; happen to crash when RBBS-PC was compiled using QB3.0.
;
; Jon Martin AIRCOMM (415) 689-2090
;
;Fix - Correct bug that did not support Implode as valid ZIP compression
;09/02/89 type.
;
; Jon Martin AIRCOMM (415) 689-2090
;
STDOUT equ 1 ;Standard Output v1.3
STDERR equ 2 ;Std Error (console) v1.3
FALSE equ 0
TRUE equ NOT FALSE
DEBUG equ FALSE
Print macro name ; display a field
mov dx,offset name
call PrintS
endm
header struc ; archive header
aMbrflag db 1AH ;unique ARC/PAK flag v1.3
aCmpMeth db 0 ; compression code
aMbrName db 13 dup (0) ; file name
aCmpSiz dw 0,0 ; file size in archive
aModDate dw 0 ; creation date
aModTime dw 0 ; creation time
aCrc16 dw 0 ; cyclic redundancy check
aUncmpSiz dw 0,0 ; true file size, bytes
header ends
ARCHDRLEN equ 29 ;size of ARC/PAK header. v1.3
;v1.3 ZIP Local file header structure:
zLocalEntry STRUC
zdig0 db 50H,4BH,03H,04H ;local file header signature 4 bytes
;(0x04034b50)
zVerMade dw ? ;version needed to extract 2 bytes
zBitflag dw ? ;general purpose bit flag 2 bytes
zCmpMeth dw ? ;compression method 2 bytes
zModTime dw ? ;last mod file time 2 bytes
zModDate dw ? ;last mod file date 2 bytes
zCrc32 dw ?,? ;crc-32 4 bytes
zCmpSiz dw ?,? ;compressed size 4 bytes
zUncmpSiz dw ?,? ;uncompressed size 4 bytes
zNameLen dw ? ;filename length 2 bytes
zExtraLen dw ? ;extra field length 2 bytes
zMbrName db ? ;filename (variable size)
;extra field (variable size)
ZLocalEntry ENDS
ZIPHDRLEN equ 30 ;length of initial ZIP hdr read v1.3
;v1.4 LZH header structure
lzhlfh STRUC ;Local file header
lUnk1 db ?,? ;char unknown1[2]; ;?
lCmpMeth db 5 dup(?) ;char method[5]; ;compression method
lCmpSiz dw ?,? ;long csize; ;compressed size
lUncmpSiz dw ?,? ;long fsize; ;uncompressed size
lModTime dw ? ;int ftime; ;last mod file time
lModDate dw ? ;int fdate; ;last mod file date
lFAttr db ? ;char fattr; ;file attributes
lUnk2 db ? ;char unknown2; ;?
lNameLen db ? ;char namelen; ;filename length
lMbrName db ? ;char *fname; ;filename
;lCrc16 dw ? ;int crc; ;crc-16
lzhlfh ENDS
LZHHDRLEN equ 22 ;not including lMbrName or lCrc16
CSEG segment public para 'CODE'
assume CS:CSEG,DS:CSEG,ES:CSEG
public ArcV
ArcV proc far
push bp ; save BASIC reg
mov bp,sp ; get parameter list pointer
mov CS:stkptr,sp ; save stack ptr
mov CS:saveds,DS ; save QB seg reg
mov CS:savees,ES ; save QB seg reg
call Start ; do our thing v1.3
; set DOS error level and exit
;v1.3a We aren't relying on the CF flag anymore to indicate errors.
; Instead, check AL.
; 0 = success
; 1 = command line parm error
; 2..6 are file-related (not found, etc.)
; 11 = Invalid format (probably didn't find a member header)
; 13 = invalid data (probably a bad file header structure)
; 18 = Unexpected EOF ('no further files to be found')
Exit: mov sp,stkptr ; restore entry stack value
push ax ;save error value v1.3
;v1.3 Numerous errors could be returned
or al,al ;no errors?
jz Exit_NoErr ;yep, ok
mov bx,offset errtbl ;assume unknown error
mov di,bx ;various error values
mov cx,ERRTBLLEN ;table length
repne scasb ;find the offset
jnz Err_TblDone ;unknown, BX has table start
dec di ;back up to actual error
sub di,bx ;current psn - start = relative nr
mov bx,di ;into BX for msg offset
Err_TblDone:
shl bx,1 ;*2 for words
Err_Unk:
add bx,offset errmsgtbl ;table of addresses
mov dx,[bx] ;ptr to string
call PrintS ;output error msg
Exit_NoErr:
mov bx,word ptr outhdl ; close listing file
cmp bl,STDERR ;never opened or STDERR? v1.3
jna Exit1 ;not a real handle v1.3
mov ah,3eh ;close file handle
int 21h
Exit1:
mov bx,word ptr archdl ;close ARC/PAK/ZIP file v1.3
or bx,bx ; if it was opened v1.3
jz Exit2 ; nope v1.3
mov ah,3EH ;close file handle v1.3
int 21H ; v1.3
Exit2: ; v1.3
;v1.3 Adding a test to insure we switched DTAs
; (so we don't blow away the caller's DTA with a vector 0:0!)
lds dx,dword ptr savedta ;get orig DTA vector
or dx,dx ;did we ever get it?
jz Exit_NoDTA ;nope
mov ax,DS ;check out seg
or ax,ax
jz Exit_NoDTA ;nope
mov ah,1ah ;set DTA
int 21h
Exit_NoDTA:
les ax,dword ptr CS:saveds ;recover calling seg regs 08/23/89
;(low word is orig DS) 08/23/89
mov ds,ax ; 08/23/89
ASSUME DS:NOTHING,ES:NOTHING ;a reminder
pop ax ;restore error level v1.3
xor ah,ah ;insure msb clear v1.3a
mov bp,sp ; parm ptr from entry
mov 6[bp],ax ;return retcd variable v1.3
pop bp
ret 6 ; clear parms from stack ' CPC151A
subttl '--- constants, equates and work areas'
page
CR equ 13
LF equ 10
BEL equ 7
TAB equ 9
STOPPER equ 0 ; end of display line indicator
ARCMARK equ 26 ; special archive marker
ARCVER equ 10 ; highest compression code used
even ;v1.3a
stkptr dw 0 ; stack pointer upon entry
arctitl db CR,LF,'Archive: ' ;keep this even v1.3a
saveds dw 0 ; QB seg reg
savees dw 0 ; QB seg reg
subttl '--- i/o control variables'
page
INBUFSZ equ 128 ;512 ; size of input buffer v1.3
;v1.3 Completely reordered these runtime variables
; so we can purge them with one fell swoop
PURGESTART equ $ ; v1.3
totsf dw 0,0 ; average stowage factor
totlen dw 0,0 ; total of file lengths
totsize dw 0,0 ; total of file sizes
totmbrs dw 0 ; total number of files
archdl dw 0 ; file handle
fileptr dw 0 ; ptr to filename part of arcname
arclen dw 0 ;full archive filename length v1.3
arcname db 76 dup (0)
outhdl dw 0 ; handle for output listing v1.3
templen dw 0 ;output filename length v1.3
temp db 76 dup (0) ; and temporary file name
filelen dw 0,0 ;absolute archive file length v1.3a
curpsn dw 0,0 ;remember current file pointer psn v1.3a
savedta dw 0,0 ; addr of QB dta
dta db 48 dup (0) ; data transfer area
even ; v1.3
PURGELEN EQU ($ - PURGESTART) SHR 1 ;amount to purge each run v1.3
; display lines for verbose
vhdr db CR,LF
db CR,LF,'Name Length Stowage SF Size now Date Time CRC '
db CR,LF,'============ ======== ======== ==== ======== ========= ====== ===='
db CR,LF ;v1.4
db STOPPER
;vline db CR,LF
vline label byte ;v1.4
vname db 14 dup (' ')
vlength db ' ' ; length in archive v1.3
vstyle db ' ' ; compression method
vfactor db ' xx% ' ; compression factor
vsize db 10 dup (' ') ; actual file bytes
vdate db 'dd ' ; creation date
vmonth db 'mmm '
vyear db 'yy '
vtime db 'hh:mm ' ; creation time
vcrc db 'xxxx' ; crc in hex
db CR,LF ;v1.4
db STOPPER
hundred dw 100 ; for computing percentages
; final totals line
vthdr db '------ --- -------- ---- --------',CR,LF ;v1.4
db '*Total ' ;v1.4
vtmbrs db ' '
vtlen db 8 dup (' '),' '
db 10 dup (' ')
vtsf db ' % '
vtsize db 8 dup (' ')
db CR,LF ; for tom
db STOPPER
sign db ' '
styles db ' ----- ' ; 1 = old, no compression
db ' ----- ' ; 2 = new, no compression
db ' Packed ' ; 3 = dle for repeat chars
db 'Squeezed' ; 4 = huffman encoding
db 'crunched' ; 5 = lz, no dle
db 'crunched' ; 6 = lz with dle
db 'Crunched' ; 7 = lz with readjust
db 'Crunched' ; 8 = lz with readjust and dle
db 'Squashed' ; 9 = 13-bit lz with no dle
db ' Crushed' ;10 = Pak10 file ---------Bob Simoneau
;v1.3 ZIP compression types:
zstyles label byte
db ' Stored' ;0 - The file is stored (no compression)
db ' Shrunk' ;1 - The file is Shrunk
db 'Reduced1' ;2 - Reduced with compression factor 1
db 'Reduced2' ;3 - Reduced with compression factor 2
db 'Reduced3' ;4 - Reduced with compression factor 3
db 'Reduced4' ;5 - Reduced with compression factor 4
db 'Imploded' ;6 - New don't know format v1.6
;v1.4 LZH compression types are already coded as 5 chars of text
; in the compressed file.
; All we need to do is pad them out to the correct width.
months db 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec '
ARCPAK = 0 ; v1.3
ZIP = 1 ; v1.4
LZH = 2 ; v1.4
ftype db ZIP ;flag which type file v1.3
;v1.4 4 types of archive file
ziptype db 'ZIP'
arctype db 'ARC'
paktype db 'PAK'
lzhtype db 'LZH' ;v1.4
larctype db 'LZS' ;v1.4 not enabled for now
;zfilesig db 50H,4BH,03H,04H ;local file header signature v1.3
;zdirsig db 50H,4BH,01H,02H ;central file header signature v1.3
ZSIG equ 4B50H ;unique ZIP signature v1.4
ZFILESIG equ 0403H ;file member signature v1.4
ZDIRSIG equ 0201H ;central file header signature v1.4
;v1.3 Centralizing errors at the exit point
; 1 = command line parm error
; 2..6 are file-related (not found, etc.)
; 11 = Invalid format (probably didn't find a member header)
; 12 = Invalid file type (not an ARC, PAK, ZIP)
; 13 = invalid data (probably a bad file header structure)
; 18 = Unexpected EOF ('no further files to be found')
errtbl db 0,1,2,3,4,5,6,11,12,13,18,25,27,29,30 ;v1.3a
ERRTBLLEN equ $ - errtbl
errmsgtbl dw msg0,msg1,msg2,msg3 ;v1.3a
dw msg4,msg5,msg6,msg11
dw msg12,msg13,msg18,msg25
dw msg27,msg29,msg30
msg0 db 'Unknown error',0
msg1 db 'Invalid function number',0
msg2 db 'Archive file not found',0
msg3 db 'Path not found',0
msg4 db 'No handle available',0
msg5 db 'Access denied',0
msg6 db 'Invalid handle',0
msg11 db 'Archive header error',0
msg12 db 'Invalid file type',0
msg13 db 'Archive format error',0
msg18 db 'No further files to be found',0
msg25 db 'Disk seek error',0
msg27 db 'Disk sector not found',0
msg29 db 'Write error',0
msg30 db 'Read error',0
subttl '--- mainline processing'
page
;
Start proc near ; v1.3
mov ax,CS ;just set ES for now v1.3
mov ES,ax
ASSUME DS:NOTHING,ES:CSEG ;a reminder v1.3a
;v1.3 Insure all variables are cleared
cld
mov di,offset PURGESTART
xor ax,ax ;clear all the variables v1.3
mov cx,PURGELEN ;nr words to clear v1.3
rep stosw ; v1.3
;v1.3 Move first parameter (output filename) into code space
mov si,word ptr 10[bp] ; ptr to parameter vector ' CPC151A
lodsw ; get string length ' CPC151A
mov cx,ax ; ' CPC151A
jcxz Copy_Parm2 ;empty, forget it v1.3
mov di,offset templen ;str length v1.3
stosw ;save length v1.3
mov si,[si] ; get string offset v1.3a
rep movsb ;copy in the string v1.3
Copy_Parm2:
;v1.3 Now copy 2d parameter (target archive filename)
mov si,word ptr 8[bp] ; ptr to parameter vector
lodsw ; get string length
mov cx,ax ; v1.3
jcxz Parm2_Done ;forget it v1.3
mov di,offset arclen ;archive name length v1.3
stosw ;save length v1.3
mov si,[si] ; get string offset v1.3
mov ah,'a' ;constant for uppercasing v1.3
Parm2_Upper: ; v1.3
lodsb ;snarf char v1.3
cmp al,ah ;need uppercasing? v1.3
jb Parm2_NoU ;nope v1.3
sub al,20H ;uppercase it v1.3
Parm2_NoU: ; v1.3
stosb ; v1.3
loop Parm2_Upper ; v1.3
Parm2_Done:
;v1.3 All done with DS
mov ax,CS ; v1.3
mov DS,ax ; v1.3
ASSUME DS:CSEG,ES:CSEG ;a reminder v1.3a
mov ax,STDERR ;assume no output filename v1.3a
cmp temp,0 ;any output filename? v1.3
jz Temp_Opened ;nope, use STDERR v1.3a
;v1.3 Forcing output file to STDERR for debugging.
;v1.3 mov al,1 ; will show usage v1.3
;v1.3 ret ;back to Exit v1.3
;v1.3a mov ax,STDERR ;force to STDERR v1.3
;v1.3a jmp short Temp_Opened ;continue v1.3
;Got_Temp:
mov dx,offset temp ; open temporary file for output
xor cx,cx ;no special attributes v1.3
mov ah,3ch ;create file
int 21h
jnb Temp_Opened ;fine v1.3
ret ;back to Exit, AL=error code v1.3
;CF set v1.3a
Temp_Opened:
mov outhdl,ax ;save handle
;v1.3 Parse the target archive name
; Separate path from name
; Insure it's an ARC, PAK or ZIP type.
mov di,offset arclen ;archive name length v1.3
mov ax,[di] ;snarf length v1.3a
inc di ;bump to name proper v1.3a
inc di ; v1.3a
mov cx,ax ;into CX for scans to come v1.3a
jcxz No_ArcName ;no length, ergo no name v1.3a
mov dx,ax ;save in DX for later v1.3
xor al,al ;will scan for AsciiZ terminator v1.3
cmp [di],al ;no name at all? v1.3
jnz Got_ArcName ;yep v1.3
No_ArcName:
mov al,2 ;'Archive file not found' v1.3
ret ;back to Exit v1.3
Got_ArcName:
;v1.3 We have some sort of target name.
; But is it a legal type?
; DX = filename length
; DI -> archive filename (arcname)
add di,dx ;+ length -> last char+1 v1.3
dec di ;back up to last char v1.3
mov bx,di ;BX -> last char v1.3
mov al,'\' ;look for normal path delimiter v1.3
mov cx,dx ;length for scan v1.3
std ;backwards scanning now v1.3
repne scasb ; v1.3
jz Got_Start ;found one v1.3
;Ugh .. tired of typing in v1.3's!
mov di,bx ;back to end
mov cx,dx ;restore length
mov al,'/' ;funny path delimiter
repne scasb
jz Got_Start ;found one
mov di,bx ;back to end .. sigh ..
mov cx,dx ;restore length
mov al,':' ;ok, how about a drive?
repne scasb
jnz No_Paths ;nope, DI -> name start
Got_Start:
inc di ;bump up to the separator
No_Paths:
inc di ;bump to the first name char
cld ;forward again
mov fileptr,di ;remember real filename start
;v1.4 You MUST specify the type .. .ARC, .PAK, .ZIP, or .LZH.
; If .ARC or .PAK, we'll use the old code to display ARC-type
; files.
;v1.4 Else if ZIP or LZH, it's a totally new format!
; We remember the type archiving format in 'ftype'.
;v1.3 DS:SI -> filename's first char.
mov al,'.' ;find the separator v1.3
mov cx,word ptr 12 ;max of 12 chars v1.3
repne scasb ;find it v1.3
jnz BadType ;forget it v1.3
mov dx,di ;save pointer to file type v1.3
;(just past the separator) v1.3
mov ax,3 ;3 chars constant
mov ftype,ZIP ;assume ZIP
mov si,offset ziptype ;is it a ZIP?
mov di,dx ;back to filename type
mov cx,ax ;3 chars
repz cmpsb ;compare
jz Got_Type ;a match
mov ftype,ARCPAK ;ok, assume ARC or PAK v1.3a
mov si,offset arctype ;is it an ARC? v1.3
mov di,dx ;back to filename type
mov cx,ax ;3 chars
repz cmpsb ;compare
jz Got_Type ;a match
mov si,offset paktype ;is it a PAK?
mov di,dx ;back to filename type
mov cx,ax ;3 chars
repz cmpsb ;compare
jz Got_Type ;a match
;v1.4 Adding .LZH types
mov ftype,LZH ;ok, assume .LZH file v1.4
mov si,offset lzhtype ;is it an LZH?
mov di,dx ;back to filename type
mov cx,ax ;3 chars
repz cmpsb ;compare
jz Got_Type ;a match
BadType:
mov al,12 ;'Invalid file type' v1.3a
ret ;back to Exit v1.3
Got_Type: ;v1.3
; find first matching file
push ES
mov ah,2fh ; get current dta ptr
int 21h ; returned in ES:bx
mov savedta,ES
mov savedta[2],bx
pop ES
mov dx,offset dta ; set local dta for murkers
mov ah,1ah
int 21h
call OpenArc ; see if archive exists
; jb ArcV_X ;nope, return, AL = error v1.3
jnb ArcV1 ;ok
jmp ArcV_X ;nope, return, AL=error v1.4
;v1.3a Display archive filename, header,
; then into a loop for each archive member.
ArcV1: mov dx,fileptr ;pointer to filename v1.3a
call PrintS ;display, CR/LF v1.3a
jb ArcV_X ;output failed v1.3a
Print vhdr
jb ArcV_X ;output failed, AL = error v1.3
ArcVNext:
IF DEBUG
Print debug1
jmp short debugj1
debug1 db 'Calling GetHdr',CR,LF,0
debugj1:
ENDIF
call GetHdr ; load next header
jb ArcV_NoHdr ;failed somehow, AL=error v1.3a
;(could be EOF, which is ok) v1.3a
IF DEBUG
Print debug2
jmp short debugj2
debug2 db 'Calling ArcVgo',CR,LF,0
debugj2:
ENDIF
call ArcVgo ;format, write out file report
jb Arcv_NoHdr ;something failed, AL=error v1.3a
IF DEBUG
Print debug3
jmp short debugj3
debug3 db 'Calling Bump_ArcPtrs',CR,LF,0
debugj3:
ENDIF
call Bump_ArcPtrs ;bump to next archive file v1.3
jnb ArcVNext ;loop if ok, else AL=error v1.3a
;(could be EOF) v1.3a
ArcV_NoHdr:
cmp archdr.aCmpMeth,0 ; archive eof?
jnz ArcV_X ;nope, something else happened v1.3
cmp totmbrs,0 ;any totals? v1.3
jz ArcV_X ;nope v1.3
push ax ;save previous error value v1.3
call Format_Totals ;yep, format and output v1.3
pop ax ;restore prev err value v1.3
ArcV_X: ret ;AL=error v1.3a
Start endp ; v1.3
;v1.3 Format, display single line for each member
; On success, return:
; CF clear
; AL = 0
; On error, return:
; CF set (because of output write fail)
; AL = error code
ArcVgo proc near
mov di,offset vname ; copy file name
mov si,offset archdr.aMbrName
mov cx,word ptr 13 ;up to 12 chars long, AsciiZ 0
ArcV3:
lodsb
or al,al ; end of name? v1.3
je ArcV4
stosb
loop ArcV3
jmp short ArcV5
ArcV4:
mov al,' ' ; pad with blanks
rep stosb
ArcV5:
; reduce the size/length to word values
mov bx,offset archdr.aCmpSiz ;-> compressed size v1.4
mov cx,[bx] ;.lo v1.4
mov dx,2[bx] ;.hi v1.4
mov bx,offset archdr.aUncmpSiz ;-> uncompressed size v1.4
mov ax,2[bx] ;.hi v1.4
mov bx,[bx] ;.lo v1.4
ArcV51: or ax,ax ; big number?
jz ArcV52 ; nope, can use it
shr ax,1 ; yup, divide by two
rcr bx,1
shr dx,1
rcr cx,1
jmp short ArcV51
ArcV52:
mov ax,bx ; low word of actual size
mov sign,' '
cmp ax,cx ; arc member is larger?
jb ArcV520
sub ax,cx ; amount saved
jmp short ArcV56
ArcV520:
sub ax,cx
neg ax
mov sign,'-'
ArcV56:
mul hundred ; to percentage
add ax,50
adc dx,0 ; round up percent
or bx,bx ; empty file?
jnz ArcV53
mov ax,100
jmp short ArcV54
ArcV53: div bx
ArcV54:
cmp ax,100 ; archive fouled?
jbe ArcV55
sub ax,ax
ArcV55:
mov di,offset vfactor-2 ;format stowage factor v1.3
call Asciify ;display AX
mov al,sign
mov vfactor,al
mov cx,word ptr 3 ;gonna need it in a sec v1.4
cmp ftype,LZH ;LZH type? (compression method v1.4
; is already text) v1.4
jnz ArcV_GetStyles ;nope v1.4
;v1.4 The LZH compression method (5 chars) is still in inbuf.
mov si,offset inbuf.lCmpMeth ;-> 5-char compression v1.4
; method string v1.4
mov di,si
add di,5 ;point to beyond chars v1.4
mov ax,' ' ;need 3 trailing blanks v1.4
stosw
stosb
mov di,offset vstyle+1 ;indent to be neat v1.4
jmp short ArcV_GotStyle ;skip v1.4
ArcV_GetStyles: ; v1.4
mov si,offset zstyles ;assume ZIP v1.3
cmp ftype,ZIP ;ZIP file? v1.3
jz ArcV55A ;yep v1.3
mov si,offset styles ;ARC or PAK v1.3
ArcV55A: ; v1.3
sub bx,bx ; determine style
mov bl,archdr.aCmpMeth
dec bl ;adjust for table offset v1.3
;v1.4 mov cl,3 ; eight bytes each entry
;v1.4 CX = 3 (eight bytes each entry)
shl bx,cl ;*8
add si,bx ;point into style table v1.3
mov di,offset vstyle
ArcV_GotStyle: ; v1.4
inc cx ;CX=4=words to move v1.4
rep movsw ; v1.3
mov bx,offset archdr.aCmpSiz ;-> compressed size v1.4
mov ax,[bx] ;.lo v1.4
mov dx,2[bx] ;.hi v1.4
mov bx,offset totsize ;-> accumulated compressed size v1.4
add [bx],ax ;.lo v1.4
adc 2[bx],dx ;.hi v1.4
mov di,offset vsize ;format file size v1.3
call Asciify_Long ; v1.3
mov bx,offset archdr.aUncmpSiz ;-> uncompressed size v1.4
mov ax,[bx] ;.lo v1.4
mov dx,2[bx] ;.hi v1.4
mov bx,offset totlen ;-> total length accumulator v1.4
add [bx],ax ;.lo v1.4
adc 2[bx],dx ;.hi v1.4
mov di,offset vlength ;format file length v1.3
call Asciify_Long ; v1.3
mov ax,archdr.aModDate ; format file date
call GetDate
mov ax,archdr.aModTime ; format file time
call GetTime
mov ax,archdr.aCrc16 ; format crc in hex
mov di,offset vcrc
call Cvh
inc totmbrs ;NOW bump total count v1.3a
Print vline ; display this file info
;(may return error) v1.3a
ret
ArcVgo endp
subttl '--- load next archive header'
page
;v1.3 Adding ZIP file searching
;v1.3a For ARC/PAK files, now testing to see if we're at the archive
; file end. If so (a proper file), return with EOF (CF set
; but AL=0).
; Archive files may have picked up some garbage on the end
; (from XMODEM xfers, whatever). We'll see if we at LEAST have
; enough data for an archive header.
; If not, assume EOF, ignoring garbage.
; If there's more than 29 bytes of garbage .. the header will be
; garbage and we're gonna report a format error .. but that's ok for now.
; Zip files have a definite ending (the central directory,
; and they'll look out for their own endings.
;
; Also returning CF and AL per any errors.
GetHdr proc near
xor ax,ax ;handy 0
mov archdr.aCmpMeth,al ;assume archive EOF
cmp ftype,ZIP ;doing ZIP files?
jnz GH_NotZip ;nope v1.4
jmp Get_ZipHdr ;yep, they look out for themselves
GH_NotZip:
cmp ftype,LZH ;doing an LZH file? v1.4
jnz GH_ArcPak_Hdr ;nope v1.4
jmp Get_LZHHdr ;yep v1.4
GH_ArcPak_Hdr: ; v1.4
;v1.3 New code
; ARC/PAK headers look like this:
;aMbrFlag db 1AH ;unique header flag
;aCmpMeth db 0 ; compression code
;aMbrName db 13 dup (0) ; file name
;aCmpSiz dw 0,0 ; file size in archive
;aModDate dw 0 ; creation date
;aModTime dw 0 ; creation time
;aCrc16 dw 0 ; cyclic redundancy check
;aUncmpSiz dw 0,0 ; true file size, bytes
mov dx,offset archdr ;read into here
mov cx,ARCHDRLEN ;nr bytes to read
mov bx,archdl ;archive file handle
mov ah,3FH ;read from file/device
int 21H
jnb GH_ChkHdr ;read ok v1.3a
ret ;return CF set, AL=error v1.3a
GH_ChkHdr:
mov bx,dx ;DS:BX -> structure start v1.3a
cmp [bx].aMbrFlag,ARCMARK ;start of header?
jne Hdr_InvalFmt ;'invalid format', exit CF set
mov al,[bx].aCmpMeth ;type compression
cmp al,ARCVER ;reasonable code?
ja Hdr_InvalFmt ;nope, funny stuff
or al,al ; archive eof?
je Hdr_RetCF ;yep, done, return CF set
;but AL=0 = not a REAL error v1.3a
cmp al,1 ; old format?
jne GetHdrX ; if so, it's short
mov si,offset archdr.aCmpSiz ; CPC15-1C
mov di,offset archdr.aUncmpSiz ; CPC15-1C
movsw ; v1.3
movsw ; v1.3
GetHdrX:
xor al,al ;return AL=0, success v1.3a
clc
ret
Hdr_InvalFmt:
mov al,0BH ;'invalid format'
Hdr_EarlyEOF: ; ;v1.4
mov [bx].aCmpMeth,al ;signal EOF or invalid format v1.4
Hdr_RetCF:
stc ;return CF set, AL=error
ret
GetHdr endp
Get_ZipHdr proc near
;v1.4 GetHdr Subroutine for ZIP files
;v1.3 Reads in ZIP file entry.
; Then scans for the unique file entry signature.
; On success:
; DS:BX -> file entry directory structure
; CF clear
; Else CF set for failure
call Read_Zip_Entry
jb Get_ZHdrX ;failed, AL=ERRORLEVEL
mov bx,offset inbuf ;use for field base
mov di,offset archdr.aCmpMeth ;moving into this structure
;v1.4 Remember, the ZIP header we'll be snarfing data from
; looks like this:
;zVerMade dw ? ;version needed to extract 2 bytes
;zBitflag dw ? ;general purpose bit flag 2 bytes
;zCmpMeth dw ? ;compression method 2 bytes
;zModTime dw ? ;last mod file time 2 bytes
;zModDate dw ? ;last mod file date 2 bytes
;zCrc32 dw ?,? ;crc-32 4 bytes
;zCmpSiz dw ?,? ;compressed size 4 bytes
;zUncmpSiz dw ?,? ;uncompressed size 4 bytes
;zNameLen dw ? ;filename length 2 bytes
;zExtraLen dw ? ;extra field length 2 bytes
;zMbrName db ? ;filename (variable size)
;extra field (variable size)
;
; and the ARC/PAK record we'll be formatting to
; looks like this:
;aMbrFlag db 1AH
;aCmpMeth db 0 ; compression code
;aMbrName db 13 dup (0) ; file name
;aCmpSiz dw 0,0 ; file size in archive
;aModDate dw 0 ; creation date
;aModTime dw 0 ; creation time
;aCrc16 dw 0 ; cyclic redunancy check
;aUncmpSiz dw 0,0 ; true file size, bytes
mov ax,[bx].zCmpMeth ;compression method
inc al ;bump to be non-0
stosb ;-> aCmpMeth
;For now, assuming a normal file name (no paths)
mov ax,[bx].zNameLen ;filename length
and ax,15 ;constrain to max 12 chars
mov cx,ax ;into CX for move
lea si,[bx].zMbrName ;pointer to actual filename
rep movsb ;do the move
xor al,al ;terminating 0
stosb
mov di,offset archdr.aCmpSiz ;bump past name
; mov ax,[bx].zCmpSiz ;compressed size.lo
; stosw ; -> aCmpSiz
; mov ax,[bx].zCmpSiz[2] ;compressed size.hi
; stosw ; -> aCmpSiz[2]
mov si,offset inbuf.zCmpSiz ;-> compressed size
movsw ;aCmpSiz.lo
movsw ;aCmpSiz.hi
mov ax,[bx].zModDate ;last mod date
stosw ; -> aModDate
mov ax,[bx].zModTime ;last mod time
stosw ; -> aModTime
mov ax,[bx].zCrc32 ;CRC-32 value.lo
stosw ; -> aCrc16
; mov ax,[bx].zUncmpSiz ;uncompressed size.lo
; stosw ; -> aUncmpSiz
; mov ax,[bx].zUncmpSiz[2] ;uncompressed size.hi
; stosw ; -> aUncmpSiz[2]
mov si,offset inbuf.zUncmpSiz ;-> uncompressed size
movsw ;aUncmpSiz.lo
movsw ;aUncmpSiz.hi
xor ax,ax ;return AX 0
clc ;return CF clear
Get_ZHdrX:
ret
Get_ZipHdr endp ;GetHdr subroutine
Get_LZHHdr proc near
;v1.4 GetHdr Subroutine for LZH headers
; LZH file header has already been read in to inbuf.
;
; If all is ok, we move the appropriate LZH fields into the
; standard ARC/PAK structure (archdr) (so far as we can).
;
; Gleaning from the LHARCDOC documentation, the 'laCmpMeth' field
; (5 characters) can be:
; '-lh0-' stored as is (no compression)
; '-lh1-' compressed by LZHuf coding
; There appear to be at least two more possible compression codes
; that may appear: "LARC type 4 and type 5" (whatever they may be!).
;
; Assuming this field will ALWAYS be text, we are NOT gonna try to
; snarf some magic code number out of the field, but will just
; protect the field (in inbuf) and move the text directly into our
; formatted display line later.
;
; The only way we can test this as an LZH header is to look
; for a '-%%%-' starting at the 2d header byte (the laCmpMeth
; field).
;
; On success:
; DS:BX -> file entry directory structure
; CF clear
; Else CF set for failure
;v1.4 LZH files don't have a decent, clean EOF header.
; We have to test for near-EOF the hard way.
mov di,offset archdr.aMbrFlag ;moving into this structure
mov ax,001AH ;fake ARC/PAK flag
stosw ; and EOF compression code
xor ax,ax ;handy 0
mov bx,offset filelen ;-> file length
mov dx,[bx] ;file length.lo
mov cx,2[bx] ;file length.hi
mov bx,offset curpsn ;for fast access
cmp cx,2[bx] ;length.hi = psn.hi?
jnz GL_AddHdr ;nope
cmp dx,[bx] ;length.lo = psn.lo?
jz GL_TrueEof ;yep, we're exactly at EOF
GL_AddHdr:
sub dx,LZHHDRLEN ;sub header length
sbb cx,ax ;0 ;handle the borrow
jb GL_Eof ;<0, beyond EOF
sub dx,[bx] ;- file psn.lo
sbb cx,2[bx] ;- file psn.hi, minus any borrows
jnb GL_NotEof ;not near end .. ok
;There must've been junk on the file end.
;However .. there ALWAYS seems to be junk on the end.
; So .. we'll return no message at all (AL=0)
;If we ever figure out how to detect a TRUE LZH EOF,
;we can enable this ERRORLEVEL=18 business.
GL_Eof:
; mov al,18 ;'No further files to be found'
GL_TrueEof:
stc ;CF set for EOF v1.4
ret
GL_NotEof:
push di ;save ptr -> archdr.aMbrName
call Read_LZH_Entry
pop di
jb Get_LHdrX ;failed, AL=ERRORLEVEL
mov bx,offset inbuf ;use for field base
;v1.4 Remember, the LZH header we'll be snarfing data from
; looks like this:
;lUnk1 db ?,? ;char unknown1[2]; ;?
;lCmpMeth db 5 dup(?) ;char method[5]; ;compression method
;lCmpSiz dw ?,? ;long csize; ;compressed size
;lUncmpSiz dw ?,? ;long fsize; ;uncompressed size
;lModTime dw ? ;int ftime; ;last mod file time
; ; (msdos format)
;lModDate dw ? ;int fdate; ;last mod file date
;lfAttr db ? ;char fattr; ;file attributes
;unknown2 db ? ;char unknown2; ;?
;lNameLen db ? ;char namelen; ;filename length
;
;lMbrName db ? ;char *fname; ;filename
;;lCrc16 dw ? ;int crc; ;crc-16
;
; and the ARC/PAK record we'll be formatting to
; looks like this:
;aMbrFlag db 1AH
;aCmpMeth db 0 ; compression code
;aMbrName db 13 dup (0) ; file name
;aCmpSiz dw 0,0 ; file size in archive
;aModDate dw 0 ; creation date
;aModTime dw 0 ; creation time
;aCrc16 dw 0 ; cyclic redundancy check
;aUncmpSiz dw 0,0 ; true file size, bytes
mov al,[bx].lNameLen ;filename length
and ax,15 ;constrain to max 12 chars
mov cx,ax ;into CX for move
mov si,offset inbuf.lMbrName ;-> actual filename
rep movsb ;do the move
xor al,al ;terminating 0
stosb
;In LZH headers, the 2-byte CRC16 word lies immediately
;after the filename.
;Snarf it now and stuff in the ARC header.
lodsw ;lCrc16
push ax ;save a sec
mov di,offset archdr.aCmpSiz ;bump past name
; mov ax,[bx].lCmpSiz ;compressed size.lo
; stosw ; -> aCmpSiz
; mov ax,[bx].lCmpSiz[2] ;compressed size.hi
; stosw ; -> aCmpSiz[2]
mov si,offset inbuf.lCmpSiz ;-> compressed size
movsw ;aCmpSiz.lo
movsw ;aCmpSiz.hi
mov ax,[bx].lModDate ;last mod date
stosw ; -> aModDate
mov ax,[bx].lModTime ;last mod time
stosw ; -> aModTime
pop ax ;CRC-16 value
stosw ; -> aCrc16
; mov ax,[bx].lUncmpSiz ;uncompressed size.lo
; stosw ; -> aUncmpSiz
; mov ax,[bx].lUncmpSiz[2] ;uncompressed size.hi
; stosw ; -> aUncmpSiz[2]
mov si,offset inbuf.lUncmpSiz ;-> uncompressed size
movsw ;aUncmpSiz.lo
movsw ;aUncmpSiz.hi
xor ax,ax ;return AX 0
clc ;return CF clear
Get_LHdrX:
ret
Get_LZHHdr endp ;GetHdr Subroutine v1.4
Read_LZH_Entry proc near ;GetHdr Subroutine v1.4
mov dx,offset inbuf ;read into here
mov cx,LZHHDRLEN ;entry structure size
;(does NOT include variable
; length filename, and the
;two CRC bytes following the
;filename)
mov bx,archdl ;file handle
call ReadZ_It ;try to read in header
;(up to filename)
jb ReadL_Eof ;failed, AL=error
mov si,dx ;structure start
mov al,'-' ;test for '-l%-' or whatever
cmp [si].lCmpMeth,al ;first part of compression
;method string?
jnz ReadL_InvalDat ;bogus, failed
cmp [si].lCmpMeth+4,al ;how about last char?
jz ReadL_Ok1 ;yep, fine
ReadL_InvalDat:
mov al,0DH ;force to 'invalid data'
ReadL_Eof:
mov archdr.aCmpMeth,al ;set per EOF or error
stc ;return CF set
ret
ReadL_Ok1:
mov dx,offset inbuf.lMbrName ;-> lMbrName psn
mov cl,inbuf.lNameLen ;length of member filename
xor ch,ch ;clear msb
call ReadZ_It ;read in the name
jb ReadL_Eof ;failed
add dx,cx ;bump buff ptr past name
mov cx,2 ;LZH CRC is a word
call ReadZ_It ;read in the CRC word
jb ReadL_Eof ;failed
ret ;success
Read_LZH_Entry endp ;GetHdr Subroutine v1.4
Read_Zip_Entry proc near ;GetHdr Subroutine
mov dx,offset inbuf ;read into here
mov cx,ZIPHDRLEN ;entry structure size
;(does NOT include filename or
; Extra fields, which are
;dynamic)
mov bx,archdl ;file handle
call ReadZ_It ;try to read in header
;(up to filename)
jb ReadZ_Eof ;failed, AL=error v1.3a
mov si,dx ;->file signature v1.4
lodsw ;snarf first 2 chars v1.4
cmp ax,ZSIG ;ZIP header? v1.4
jnz ReadZ_InvalDat ;nope, bogus v1.4
lodsw ;file or central sig v1.4
cmp ax,ZFILESIG ;next member? v1.4
jz ReadZ_Ok1 ;yep, fine v1.4
cmp ax,ZDIRSIG ;central directory? v1.4
;(means we're done) v1.4
mov al,0 ;assume yes, EOF v1.4
jz ReadZ_Eof ;yep v1.4
ReadZ_InvalDat:
mov al,0DH ;'Invalid data' v1.4
ReadZ_Eof: ; v1.3a
mov archdr.aCmpMeth,al ;set per EOF or error v1.3a
stc ;return CF set v1.3a
ret
ReadZ_Ok1:
mov dx,offset inbuf.zMbrName ;move to zFilename psn
mov cx,inbuf.zNameLen ;length of member filename
;fall thru to ... v1.3a
;v1.4 Common subroutine for ReadZ and Read_LZH
; DX -> buffer
; CX = bytes to read
; BX MUST have archdl .. so protect BX!
ReadZ_It:
mov ah,3FH ;read from file/device
int 21H
jb ReadZ_ItX ;failed, error in AX v1.3a
;v1.4 We'll update our curpsn file pointers later
; when we try to read past compressed file contents.
;v1.4 add curpsn,ax ;bump current file ptr v1.3a
;by amount read v1.3a
;v1.4 adc word ptr curpsn[2],0 ;bump psn.hi if carry v1.3a
cmp ax,cx ;read all we expected?
mov ax,0 ;clear AX v1.3a
jz ReadZ_ItX ;yep, return CF clear v1.3a
mov al,0BH ;assume unexpected EOF
;('invalid format')
stc
ReadZ_ItX:
ret ;CF, AL set per error v1.3a
Read_Zip_Entry endp ;GetHdr subroutine
;v1.3 Common subroutine
; Bumps archive file pointers to next entry
; On success, return:
; CF clear
; AL = 0
; On failure (e.g., couldn't move ptrs), return:
; CF set
; AL = error
Bump_ArcPtrs proc near
cmp ftype,ZIP ;ZIP file? v1.3
jz Next_ZEntry ;bump file ptr to next entry v1.3
;v1.3 Entirely new code
mov bx,offset archdr.aCmpSiz ;-> encoded file length v1.4
mov dx,[bx] ;.lo v1.4
mov cx,2[bx] ;.hi
jmp short Bump_Common ;common code
;v1.3 Positions ZIP file pointer to next local entry.
; We've already read in the entire header, plus the filename,
; so the file pointer should be just beyond the filename
; (at the Extra field).
; Move file pointers beyond the Extra field, and then past
; the actual entry data (the compressed size).
Next_ZEntry:
mov bx,offset inbuf ;point back to structure
mov dx,[bx].zCmpSiz ;size.lo
mov cx,[bx].zCmpSiz[2] ;size.hi
add dx,[bx].zExtraLen ;add in extra field length
adc cx,0 ;in case of carry
Bump_Common:
mov bx,archdl ;file handle
mov ax,4201H ;move pointer from current loc
int 21H
jb Bump_X ;seek error v1.3a
;return CF set, AL=error v1.3a
;v1.4 Updating curpsn variables now
; so the NEXT GetHdr call will have current data.
mov bx,offset curpsn
mov [bx],ax
mov 2[bx],dx
xor ax,ax ;AX,CF clear v1.3a
Bump_X:
ret
Bump_ArcPtrs endp
;v1.3 Formats, displays totals
Format_Totals proc near
mov ax,totmbrs ;total members v1.3
mov di,offset vtmbrs-2 ;format total members v1.3
call Asciify ; v1.3
mov bx,offset totlen ;-> total actual file size v1.4
mov ax,[bx] ;.lo v1.4
mov dx,2[bx] ;.hi v1.4
push ax ;save totlen.lo v1.4
push dx ; and totlen.hi v1.4
mov di,offset vtlen ;format total actual file size v1.3
call Asciify_Long ; v1.3
mov bx,offset totsize ;-> total compressed file sizes v1.4
mov ax,[bx] ;.lo v1.4
mov dx,2[bx] ;.hi v1.4
push ax ;save totsize.lo v1.4
push dx ; and totsize.hi v1.4
mov di,offset vtsize ;format total archive file size v1.3
call Asciify_Long ; v1.3
; reduce the total size/length to word values
pop dx ;totsize.hi v1.4
pop cx ;totsize.lo v1.4
pop ax ;totlen.hi v1.4
pop bx ;totlen.lo v1.4
ArcV2b: or ax,ax ; big number?
jz ArcV2c ; nope, can use it
shr ax,1 ; yup, divide by two
rcr bx,1
shr dx,1
rcr cx,1
jmp short ArcV2b
ArcV2c:
mov ax,bx
mov sign,' ' ; whata kludge
cmp ax,cx ; arc is bigger than orig?
jb ArcV2c1
sub ax,cx ; amount saved
jmp short ArcV2f
ArcV2c1:
sub ax,cx
neg ax
mov sign,'-'
ArcV2f:
mul hundred ; to percentage
add ax,50
adc dx,0 ; round up percent
or bx,bx ; empty file?
jnz ArcV2d
mov ax,100
jmp short ArcV2e
ArcV2d: div bx
ArcV2e:
mov di,offset vtsf-2 ;format stowage factor v1.3
call Asciify ;AX v1.3
mov al,sign
mov vtsf,al
Print vthdr ; display totals
ret
Format_Totals endp
OpenArc proc near ; open new archive
mov dx,offset arcname
mov ax,3d00h ; for input
int 21h
jnb Open_GetSize ;opened ok v1.3a
ret ;return CF set, AL=error v1.3a
Open_GetSize:
mov bx,ax ;handle into BX v1.3a
mov archdl,ax ; save file handle
;v1.3a We get the total file size now for later EOF testing.
xor dx,dx ;0 offset
xor cx,cx
mov ax,4202H ;from file end
int 21H
mov filelen,ax ;length.low
mov filelen[2],dx ;length.hi
xor cx,cx ;back to start
xor dx,dx
mov ax,4200H ;psn file pointer from start
int 21H
ret ;CF should be clear
OpenArc endp
ClosArc proc near
mov bx,archdl ; previous handle
or bx,bx ; already open?
jz Closed
mov ah,3eh ; yes, so close it
int 21H
Closed: mov archdl,0 ;flag as closed
ret
ClosArc endp
;
; print null-terminated (AsciiZ) string like int 21h function 9
; Enter with DS:DX -> AsciiZ string
; destroys AX
; On success, return:
; CF clear
; AL = 0
; On failure (write fail), return:
; CF set
; AL = error
PrintS proc near
push di ;v1.3
push bx
push cx
mov cx,0FFFFH ;max scan v1.3
xor al,al ;handy 0 v1.3
mov di,dx ;string start v1.3
repne scasb ;find the terminator v1.3
inc cx ;adjust v1.3
not cx ;CX=length v1.3
mov bx,outhdl ; using std out or temp file
or bx,bx ;never opened? v1.3
jnz Print_S1 ;nope, we got a handle v1.3
inc bx ;make it StdErr v1.3
inc bx
Print_S1: ; v1.3
mov ah,40h ; write to file
int 21h
jnb PrintS_Done ;fine v1.3
;v1.3 What happens if we're trying to write to an output file
; and THAT fails? Even error msgs can't get out.
; We switch to StdErr, that's what!
mov di,ax ;save error level v1.3a
mov bx,STDERR ;force to STdErr v1.3a
mov outhdl,bx ;and for future output v1.3a
mov ah,40H ;write to STDOUT v1.3a
int 21H ;(CX,DX unchanged) v1.3a
mov ax,di ;restore orig error v1.3a
stc ;return CF set v1.3a
PrintS_Done:
pop cx ; recover registers
pop bx
pop di
ret
PrintS endp
page
;
; format the time (in AX)
time record hour:5,min:6,sec:5 ;packed time
GetTime proc near ;format the date
mov di,offset vtime
or ax,ax ;it is zero?
jz GotTime
push ax ;save date
and ax,mask hour ;get hour part
mov cl,hour ;bits to shift
shr ax,cl
call Cnvrt1
stosw
mov al,':'
stosb
GT3: pop ax ;get the time back
and ax,mask min ;get min part
mov cl,min ;bits to shift
call Cnvrt
stosw
GotTime:ret
GetTime endp
Cnvrt2 proc near ;convert to ascii
call Cnvrt
cmp al,'0' ;suppress leading zero
jne Cnvrtd
mov al,' '
ret
Cnvrt: shr ax,cl
Cnvrt1: aam ;make al into bcd
or ax,'00' ; and to ascii
xchg al,ah
Cnvrtd: ret
Cnvrt2 endp
page
;
; format the date (in AX)
date record yr:7,mo:4,dy:5 ;packed date
GetDate proc near ;format the date
or ax,ax ;is it zero?
jz GotDate
push ax ;save date
and ax,mask yr ;get year part
mov cl,yr ;bits to shift
call Cnvrt
mov di,offset vyear
or al,'8' ;adjust for base year
stosw
pop bx ;get the date back
push bx ;save it
and bx,mask mo ;get month part
mov cl,mo ;bits to shift
shr bx,cl
add bx,bx ; form month table index
add bx,bx
lea si,word ptr months-4[bx]
mov cx,word ptr 3
mov di,offset vmonth
rep movsb
pop ax ;get the date back
and ax,mask dy ;get day part
mov cl,dy ;bits to shift
call Cnvrt
mov di,offset vdate
stosw
GotDate:ret
GetDate endp
page
;
;v1.3 A severely hacked single/double precision number conversion function.
; Originally from JMODEM, but severely hacked by Toad Hall.
; ES:DI -> string
; Destroys everything almost.
;Enter here if integer in AX
Asciify proc near
xor dx,dx ; clear fake long.hi
mov si,ax ;move integer into SI
xor ah,ah ;clear msb (flag)
jmp short Ascii_Ax ;jump into the code
;Enter here if long integer in DX:AX.
Asciify_Long:
mov si,ax ;move long.lo into SI
xor ah,ah ;clear msb (flag)
Comment ~
MOV CX,3B9AH ; Get billions
MOV BX,0CA00H
CALL Subtr ; Subtract them out
MOV CX,05F5H ; Get hundred-millions
MOV BX,0E100H
CALL Subtr ; Subtract them out
Comment ends ~
and dx,4FFH ;seems likely v1.3
MOV CX,word ptr 0098H ; Get ten-millions
MOV BX,9680H
CALL Subtr ; Subtract them out
MOV CX,word ptr 000FH ; Get millions
MOV BX,4240H
CALL Subtr ; Subtract them out
MOV CX,word ptr 1 ; Get hundred-thousands
MOV BX,86A0H
CALL Subtr ; Subtract them out
Ascii_Ax:
xor cx,cx ; Get ten-thousands
MOV BX,2710H
CALL Subtr ; Subtract them out
MOV BX,03E8H
CALL Subtr ; Subtract them out
MOV BX,word ptr 0064H
CALL Subtr ; Subtract them out
MOV BX,word ptr 10
CALL Subtr ; Subtract them out
mov ax,si ;residual in SI
add AL,'0' ; Add bias to residual
stosb ; Put in the string
RET
;Common subroutine for Asciify
Subtr: mov al,'0'-1
Subtr1: INC al ; Bump the digit character
SUB si,BX ; Dword subtraction
SBB DX,CX
JNB Subtr1 ; Continue until a carry
ADD si,BX ; One too many, add back
ADC DX,CX ; and the remainder
cmp al,'0'
jnz Subtr2 ;nope, turn off leading flag, stuff
or ah,ah ;no more leading spaces?
jnz Sub_Stuff ;right, stuff the '0'
mov al,' ' ;make it neat with leading spaces
Sub_Stuff:
stosb ;stuff the char
RET
Subtr2: inc ah ;turn off leading space flag
stosb
ret
Asciify ENDP
;v1.3a Convert 16-bit binary word in AX
; to hex ASCII string at ES:DI
; (No need to save any registers)
hexchar db '0123456789ABCDEF'
Cvh proc near
mov si,offset hexchar ;for faster access v1.3a
mov dx,ax ; save 16-bits
mov bl,dh ; third nibble
mov cx,0F04H ;CL=4 for shifting, v1.3a
;CH=0FH for masking v1.3a
shr bl,cl
mov al,[si][bx] ;snarf hex char v1.3a
stosb
mov bl,dh ; last nibble
and bl,ch ;0fh ; v1.3a
mov al,[si][bx] ;snarf hex char v1.3a
stosb
mov bl,dl ; first nibble
sub bh,bh
shr bl,cl ; isolate (CL still 4) v1.3a
mov al,[si][bx] ;snarf hex char v1.3a
stosb
mov bl,dl ; second nibble
and bl,ch ;0fh ; isolate v1.3a
mov al,[si][bx] ;snarf hex char v1.3a
stosb
ret
Cvh endp
subttl '--- i/o data areas'
ArcV endp
archdr db 30 dup (0) ; i/o area for a header v1.3a
inbuf db INBUFSZ dup (0) ;just big enough for ZIP
;directories and filenames v1.3a
CSEG ENDS
END